/*
CTC协议的数据流处理模块
根据https://gitee.com/GMSA/CTC文档定义
包括缓冲区结构体的定义
从缓冲区读取数据uint16_t,uint32_t等数据类型的读取与写入
缓冲区分为发送缓冲区与接收缓冲区,缓冲数据进行回环存储,并标记有效字节的起始位置和结束位置
当有新的数据需要写入缓冲区时会变更结束位置,如果缓冲区已满需要返回写入异常
当有新的数据需要读出缓冲区时会变更起始位置,如果缓冲区已空需要返回读取异常
*/
#ifndef CTC_BUFFER_H
#define CTC_BUFFER_H

#include <stdint.h>
#include <string.h>

#define CTCBUFFERLENGTH 512  //发送缓冲区长度

/// @brief 数据流控制结构体
typedef struct {
    uint8_t data[CTCBUFFERLENGTH]; // 缓冲数据
    uint16_t startpos;           // 有效数据的起始位置
    uint16_t endpos;             // 有效数据的结束位置
    uint8_t lock;         // 自旋锁
    uint16_t readpos;             // 当前处理位置    
} CTCBuffer;

/// @brief 缓冲函数结果
typedef enum {
    CTC_BUFFER_SUCCESS     = 0x00, // 成功
    CTC_BUFFER_FULL  = 0x01, // 缓冲器已满
    CTC_BUFFER_EMPTY     = 0x02, // 无数据
    CTC_BUFFER_OVERFLOW       = 0x03, // 数据溢出
    CTC_BUFFER_DATAMISSING   = 0x04, // 数据缺失
    CTC_BUFFER_PARSE_HEADNOTFOUND   = 0x05, // 包头未找到
    CTC_BUFFER_PARSE_CRCERROR   = 0x06, // CRC错误
    CTC_BUFFER_PARSE_WAITMORE   = 0x07, // 等待更多数据
    CTC_BUFFER_CMDNOTMATCH   = 0x08, // 命令不匹配
} CTC_BufferResult;

/// @brief 初始化清空缓冲区
/// @param buf 缓冲区对象
void CTCBuffer_Init(CTCBuffer* buf);

/// @brief 自旋锁加锁
void CTCBuffer_Lock(CTCBuffer *buf);

/// @brief 自旋锁解锁
void CTCBuffer_Unlock(CTCBuffer *buf);

/// @brief 获取缓冲区有效数据长度
/// @param buf 缓冲区对象
/// @return  返回缓冲区有效数据长度
uint16_t CTCBuffer_DataLength(CTCBuffer* buf);

/// @brief 获取当前可读取数据长度
/// @param buf 缓冲区对象
/// @return  返回缓冲区可读取数据长度
uint16_t CTCBuffer_CanReadDataLength(CTCBuffer* buf);

/// @brief 获取缓冲区空闲长度
/// @param buf 缓冲区对象
/// @return  返回缓冲区空闲长度
uint16_t CTCBuffer_FreeLength(CTCBuffer* buf);

/// @brief 从缓冲区读取2字节数字
/// @param buf 缓冲区对象
/// @param val 结果指针
/// @return 读取结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_ReadUint16(CTCBuffer* buf,uint16_t *val);

/// @brief 从缓冲区读取4字节数字
/// @param buf 缓冲对象
/// @param val 结果指针
/// @return 读取结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_ReadUint32(CTCBuffer* buf, uint32_t *val);

/// @brief 从缓冲区读取1字节数字
/// @param buf 缓冲对象
/// @param val 结果指针
/// @return 读取结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_ReadUint8(CTCBuffer* buf, uint8_t *val);

/// @brief 批量写入数据
/// @param buf 缓冲对象
/// @param data 写入数据指针
/// @param length 写入长度
/// @return 写入结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_Write(CTCBuffer* buf, const uint8_t* data, uint8_t length);

/// @brief 批量读取数据
/// @param buf 缓冲对象
/// @param data 数据指针
/// @param length 读取长度
/// @return 读取结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_Read(CTCBuffer* buf, uint8_t* data, uint8_t length);

/// @brief 写入2字节数字
/// @param buf 缓冲对象
/// @param val 写入的值
/// @return 写入结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_WriteUint16(CTCBuffer* buf,uint16_t val);

/// @brief 写入4字节数字
/// @param buf 缓冲对象
/// @param val 写入值
/// @return 写入结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_WriteUint32(CTCBuffer* buf,uint32_t val);

/// @brief 写入1字节数字
/// @param buf 缓冲对象
/// @param val 写入的值
/// @return 写入结果,参考CTC_BufferResult
CTC_BufferResult CTCBuffer_WriteUint8(CTCBuffer* buf, uint8_t val);

/// @brief 结束当前读取操作,更新有效数据起始位置
void CTCBuffer_EndRead(CTCBuffer *buf);

/// @brief 开始读取操作,保存当前读取位置
void CTCBuffer_StartRead(CTCBuffer *buf);

/// @brief 写入CTC消息
/// @param buf 缓冲对象
/// @param portid 端口ID,参考CTC_DEFALUT_PORTID
/// @param cmdid 命令标识
/// @param transactionId 事务ID
/// @param msgdata 消息数据指针
/// @param msglen 消息数据长度
/// @return 返回状态码,参考CTC_BufferStatus
CTC_BufferResult CTCBuffer_WriteMsgToSendBuffer(CTCBuffer* buf,uint8_t portid,uint16_t cmdid,uint32_t transactionId,const uint8_t* msgdata,uint8_t msglen);

/// @brief 读取要发送指令,但不删除
/// @param sendbuf 缓冲对象
/// @param msgdata 消息数据指针
/// @param msglen 消息数据长度
/// @return 返回状态码,参考CTC_BufferStatus
CTC_BufferResult CTCBuffer_ReadCommandFromSendBuffer(CTCBuffer* sendbuf, uint8_t* msgdata,uint8_t* length,uint8_t *sendtimes);

/// @brief 清除第一个要发送的指令
/// @param sendbuf 缓冲对象
/// @param cmdid 命令ID
/// @param transactionid 事务ID
/// @return 返回状态码,参考CTC_BufferStatus
CTC_BufferResult CTCBuffer_DeleteFirstCommandFromSend(CTCBuffer* sendbuf,uint16_t cmdid,uint32_t transactionid);

/// @brief 重置发送缓冲区的发送次数
/// @param sendbuf 缓冲对象
void CTCBuffer_ResetSendTimes(CTCBuffer* sendbuf);

/// @brief 使用CTC协议解析接收缓冲区数据
/// @param revicebuf 接收缓冲区对象
/// @param portid 端口ID指针
/// @param cmdid 命令ID指针
/// @param transactionid 事务ID指针
/// @param datafield 数据字段指针
/// @param datalen 数据长度指针
/// @return 返回状态码,参考CTC_BufferStatus
CTC_BufferResult CTCBuffer_ParseFromReceiveBuffer(CTCBuffer *revicebuf, uint8_t *portid, uint16_t *cmdid, uint32_t *transactionid, uint8_t *datafield, uint8_t *datalen);


/// @brief 组装ACK数据
/// @param buffer 缓冲字节数字指针
/// @param portid 端口ID
/// @param cmdid 命令ID
/// @param transactionId 事务ID
/// @param result 结果码,参考CTC_AckResult
void CTCBuffer_AssembleAckData(uint8_t* buffer, uint8_t portid,uint16_t cmdid, uint32_t transactionId, uint8_t result);


/// @brief 判断数据是否全等于0
/// @param data 数据指针
/// @param length 数据长度
/// @return 全等于0返回1,否则返回0
uint8_t CTCBuffer_IsAllZero(const uint8_t* data,uint8_t length);

/// @brief 将字节数组指针前两个字节拼接成一个16位整数
uint16_t CTCBuffer_BytesToUint16(const uint8_t* data);

/// @brief 将字节数组指针前四个字节拼接成一个32位整数
uint32_t CTCBuffer_BytesToUint32(const uint8_t* data);

/// @brief 填充uint16到字节数组指针前两个字节
void CTCBuffer_Uint16ToBytes(uint16_t val, uint8_t* data);

/// @brief 填充uint32到字节数组指针前四个字节
void CTCBuffer_Uint32ToBytes(uint32_t val, uint8_t* data);

#endif // CTC_BUFFER_H
